#include "stdafx.h"
#include "net/TCPServer.hpp"
#include "thread/errorhandler.hpp"
#include "stdlib/timespan.hpp"
using JHCPP::stdlib::CTimeSpan;

NET_NAMESPACE_BEGIN

CTCPServer::CTCPServer(CTCPServerConnectionFactory::Ptr pFactory, UInt16 portNumber, CTCPServerParams::Ptr pParams)
	: m_socket(CServerSocket(portNumber)),
	m_thread(threadName(m_socket)),
	m_stopped(true)
{	
	CThreadPool& pool = CThreadPool::defaultPool();
	if (pParams)
	{
		int toAdd = pParams->getMaxThreads() - pool.capacity();
		if (toAdd > 0) 
			pool.addCapacity(toAdd);
	}
	m_pDispatcher = new CTCPServerDispatcher(pFactory, pool, pParams);
}

CTCPServer::CTCPServer(CTCPServerConnectionFactory::Ptr pFactory, const CServerSocket& socket, CTCPServerParams::Ptr pParams)
	: m_socket(socket),
	m_thread(threadName(socket)),
	m_stopped(true)
{
	CThreadPool& pool = CThreadPool::defaultPool();
	if (pParams)
	{
		int toAdd = pParams->getMaxThreads() - pool.capacity();
		if (toAdd > 0) 
			pool.addCapacity(toAdd);
	}
	m_pDispatcher = new CTCPServerDispatcher(pFactory, pool, pParams);
}

CTCPServer::CTCPServer(CTCPServerConnectionFactory::Ptr pFactory, CThreadPool& threadPool, const CServerSocket& socket, CTCPServerParams::Ptr pParams)
	: m_socket(socket),
	m_pDispatcher(new CTCPServerDispatcher(pFactory, threadPool, pParams)),
	m_thread(threadName(socket)),
	m_stopped(true)
{
}

CTCPServer::~CTCPServer()
{
	try
	{
		stop();
		m_pDispatcher->release();
	}
	catch (...)
	{
		jh_unexpected();
	}
}

const CTCPServerParams& CTCPServer::params() const
{
	return m_pDispatcher->params();
}

void CTCPServer::start()
{
	jh_assert(m_stopped);

	m_stopped = false;
	m_thread.start(*this);
}

void CTCPServer::stop()
{
	if (!m_stopped)
	{
		m_stopped = true;
		m_thread.join();
		m_pDispatcher->stop();
	}
}

int CTCPServer::currentThreads() const
{
	return m_pDispatcher->currentThreads();
}

int CTCPServer::maxThreads() const
{
	return m_pDispatcher->maxThreads();
}

int CTCPServer::totalConnections() const
{
	return m_pDispatcher->totalConnections();
}

int CTCPServer::currentConnections() const
{
	return m_pDispatcher->currentConnections();
}

int CTCPServer::maxConcurrentConnections() const
{
	return m_pDispatcher->maxConcurrentConnections();
}

int CTCPServer::queuedConnections() const
{
	return m_pDispatcher->queuedConnections();
}

int CTCPServer::refusedConnections() const
{
	return m_pDispatcher->refusedConnections();
}

const CServerSocket& CTCPServer::socket() const
{
	return m_socket;
}

UInt16 CTCPServer::port() const
{
	return m_socket.address().port();
}

void CTCPServer::run()
{
	while (!m_stopped)
	{
		CTimeSpan timeout(250000);
		if (m_socket.poll(timeout, CSocket::SELECT_READ))
		{
			try
			{
				CStreamSocket ss = m_socket.acceptConnection();
				// enabe nodelay per default: OSX really needs that
				ss.setNoDelay(true);
				m_pDispatcher->enqueue(ss);
			}
			catch (CException& exc)
			{
				CErrorHandler::handle(exc);
			}
			catch (std::exception& exc)
			{
				CErrorHandler::handle(exc);
			}
			catch (...)
			{
				CErrorHandler::handle();
			}
		}
	}
}

std::string CTCPServer::threadName(const CServerSocket& socket)
{
	std::string name("TCPServer: ");
	name.append(socket.address().toString());

	return name;
}

NET_NAMESPACE_END
